#include "bsp_rtc.h"
#include <stdlib.h>
#include <stdio.h>
#include "bsp_usart.h"

__IO uint32_t prescaler_a = 0;
__IO uint32_t prescaler_s = 0;

const char _week_day[][8] = {
	" ",
	"Monday",
	"Thursday",
	"Wednsday",
	"Tuesday",
	"Friday",
	"Satday",
	"Sunday"};

void RTC_Init(void)
{
	uint32_t RTCSRC_FLAG = 0;
	
	rcu_periph_clock_enable(RCU_PMU);
	pmu_backup_write_enable();

    RTC_Preconfig();
    /* get RTC clock entry selection */
    RTCSRC_FLAG = GET_BITS(RCU_BDCTL, 8, 9);	
	
    /* check if RTC has aready been configured */
    if((RTC_CONFIG_FLAG != RTC_BKP0) || (0x00 == RTCSRC_FLAG)){
        /* backup data register value is not correct or not yet programmed
        or RTC clock source is not configured (when the first time the program 
        is executed or data in RCU_BDCTL is lost due to Vbat feeding) */
        RTC_Setup();
    }
	else
	{
        /* detect the reset source */
        if (RESET != rcu_flag_get(RCU_FLAG_PORRST))
		{
            printf("power on reset occurred....\r\n");
        }
		else if (RESET != rcu_flag_get(RCU_FLAG_EPRST))
		{
            printf("external reset occurred....\r\n");
        }
        printf("no need to configure RTC....\r\n");

        RTC_ShowTime();
	}
	rcu_all_reset_flag_clear();
}

/*!
    \brief      use hyperterminal to setup RTC time and alarm
    \param[in]  none
    \param[out] none
    \retval     none
*/
// must call RTC_Init() first
void RTC_Setup(void)
{
    /* setup RTC time value */
    uint8_t tmp_hh = 0xFF, tmp_mm = 0xFF, tmp_ss = 0xFF;
	uint8_t tmp_year = 0xFF, tmp_mon = 0xFF, tmp_day = 0xFF, tmp_wk = 0xFF;
	rtc_parameter_struct   rtc_initpara;
	
    rtc_initpara.factor_asyn = prescaler_a;
    rtc_initpara.factor_syn = prescaler_s;
    rtc_initpara.year = 0x16;
    rtc_initpara.day_of_week = RTC_SATURDAY;
    rtc_initpara.month = RTC_APR;
    rtc_initpara.date = 0x30;
    rtc_initpara.display_format = RTC_24HOUR;
    rtc_initpara.am_pm = RTC_AM;

    /* current date input */
    printf("=======Configure RTC Time========\r\n");
    printf("  please input year:\r\n");
    while (0xFF == tmp_year){
        tmp_year = usart_input_threshold(99);
        rtc_initpara.year = tmp_year;
    }
    printf("  %0.2x\r\n", tmp_year);

    printf("  please input month:\r\n");
    while (0xFF == tmp_mon){
        tmp_mon = usart_input_threshold(12);
        rtc_initpara.month = tmp_mon;
    }
    printf("  %0.2x\r\n", tmp_mon);

    printf("  please input date:\r\n");
    while (0xFF == tmp_day){
        tmp_day = usart_input_threshold(59);
        rtc_initpara.date = tmp_day;
    }
    printf("  %0.2x\r\n", tmp_day);

    printf("  please input the day of week:\r\n");
    while (0xFF == tmp_wk){
        tmp_wk = usart_input_threshold(7);
        rtc_initpara.day_of_week = tmp_wk;
    }
    printf("  %0.2x\r\n", tmp_wk);
	
    /* current time input */
    printf("  please input hour:\r\n");
    while (0xFF == tmp_hh){
        tmp_hh = usart_input_threshold(23);
        rtc_initpara.hour = tmp_hh;
    }
    printf("  %0.2x\r\n", tmp_hh);

    printf("  please input minute:\r\n");
    while (0xFF == tmp_mm){
        tmp_mm = usart_input_threshold(59);
        rtc_initpara.minute = tmp_mm;
    }
    printf("  %0.2x\r\n", tmp_mm);

    printf("  please input second:\r\n");
    while (0xFF == tmp_ss){
        tmp_ss = usart_input_threshold(59);
        rtc_initpara.second = tmp_ss;
    }
    printf("  %0.2x\r\n", tmp_ss);

    /* RTC current time configuration */
    if(ERROR == rtc_init(&rtc_initpara)){
        printf("\r\n** RTC time configuration failed! **\r\n");
    }else{
        printf("\r\n** RTC time configuration success! **\r\n");
        RTC_ShowTime();
        RTC_BKP0 = RTC_CONFIG_FLAG;
    }
}

void RTC_AlarmSetup(void)
{
    /* setup RTC alarm value */
    uint32_t tmp_hh = 0xFF, tmp_mm = 0xFF, tmp_ss = 0xFF;
	rtc_alarm_struct  rtc_alarm;
	
    rtc_alarm_disable(RTC_ALARM0);
    printf("=======Input Alarm Value=======\r\n");
    rtc_alarm.alarm_mask = RTC_ALARM_DATE_MASK|RTC_ALARM_HOUR_MASK|RTC_ALARM_MINUTE_MASK;
    rtc_alarm.weekday_or_date = RTC_ALARM_DATE_SELECTED;
    rtc_alarm.alarm_day = 0x31;
    rtc_alarm.am_pm = RTC_AM;

    /* RTC alarm input */
    printf("  please input Alarm Hour:\r\n");
    while (0xFF == tmp_hh){
        tmp_hh = usart_input_threshold(23);
        rtc_alarm.alarm_hour = tmp_hh;
    }
    printf("  %0.2x\r\n", tmp_hh);

    printf("  Please Input Alarm Minute:\r\n");
    while (0xFF == tmp_mm){
        tmp_mm = usart_input_threshold(59);
        rtc_alarm.alarm_minute = tmp_mm;
    }
    printf("  %0.2x\r\n", tmp_mm);

    printf("  Please Input Alarm Second:\r\n");
    while (0xFF == tmp_ss){
        tmp_ss = usart_input_threshold(59);
        rtc_alarm.alarm_second = tmp_ss;
    }
    printf("  %0.2x", tmp_ss);

    /* RTC alarm configuration */
    rtc_alarm_config(RTC_ALARM0,&rtc_alarm);
    printf("\r\n** RTC Set Alarm Success!  **\r\n");
    RTC_ShowAlarm();

    rtc_interrupt_enable(RTC_INT_ALARM0);
    rtc_alarm_enable(RTC_ALARM0);
	
    /* RTC alarm interrupt configuration */
    exti_init(EXTI_17,EXTI_INTERRUPT,EXTI_TRIG_RISING);
    nvic_irq_enable(RTC_Alarm_IRQn,0,0);
	
    rtc_flag_clear(RTC_FLAG_ALRM0);
    exti_flag_clear(EXTI_17);
}

/*!
    \brief      RTC configuration function
    \param[in]  none
    \param[out] none
    \retval     none
*/
void RTC_Preconfig(void)
{
    #if defined (RTC_CLOCK_SOURCE_IRC32K)
          rcu_osci_on(RCU_IRC32K);
          rcu_osci_stab_wait(RCU_IRC32K);
          rcu_rtc_clock_config(RCU_RTCSRC_IRC32K);

          prescaler_s = 0x13F;
          prescaler_a = 0x63;
    #elif defined (RTC_CLOCK_SOURCE_LXTAL)
          rcu_osci_on(RCU_LXTAL);
          rcu_osci_stab_wait(RCU_LXTAL);
          rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);

          prescaler_s = 0xFF;
          prescaler_a = 0x7F;
    #else
    #error RTC clock source should be defined.
    #endif /* RTC_CLOCK_SOURCE_IRC32K */

    rcu_periph_clock_enable(RCU_RTC);
    rtc_register_sync_wait();
}

/*!
    \brief      display the current time
    \param[in]  none
    \param[out] none
    \retval     none
*/
void RTC_ShowTime(void)
{
    uint32_t time_subsecond = 0;
    uint8_t subsecond_ss = 0,subsecond_ts = 0,subsecond_hs = 0;
	rtc_parameter_struct   rtc_time;

    rtc_current_time_get(&rtc_time);

    /* get the subsecond value of current time, and convert it into fractional format */
    time_subsecond = rtc_subsecond_get();
    subsecond_ss=(1000-(time_subsecond*1000+1000)/400)/100;
    subsecond_ts=(1000-(time_subsecond*1000+1000)/400)%100/10;
    subsecond_hs=(1000-(time_subsecond*1000+1000)/400)%10;

	printf("Current date: %0.2x-%0.2x-%0.2x; %s\r\n", \
          rtc_time.year, rtc_time.month, rtc_time.date, _week_day[rtc_time.day_of_week]);
    printf("Current time: %0.2x:%0.2x:%0.2x.%d%d%d \r\n", \
          rtc_time.hour, rtc_time.minute, rtc_time.second, \
          subsecond_ss, subsecond_ts, subsecond_hs);
}

/*!
    \brief      display the alram value
    \param[in]  none
    \param[out] none
    \retval     none
*/
void RTC_ShowAlarm(void)
{
	rtc_alarm_struct  rtc_alarm;
    rtc_alarm_get(RTC_ALARM0,&rtc_alarm);
    printf("The alarm: %0.2x:%0.2x:%0.2x \r\n", rtc_alarm.alarm_hour, rtc_alarm.alarm_minute,\
           rtc_alarm.alarm_second);
}
